/********************************************************************************************
*            Copyright (c) 2013. All Rights Reserved.
*
*
* 文件名称:   port_task.c
* 描    述:  
* 当前版本:   V1.0
* 日    期:   2021/01/12
* 创 建 人:      杨小珛
* 
*********************************************************************************************/
#include "port_task.h"
#include "mon_task.h"
#include "power_task.h"
#include "log_task.h"

GaozMutexHandle_t gpio_input_mutex; 
GaozMutexHandle_t gpio_adc_mutex; 

gpio_input_state_t  gpio_input_st;      /*定义外部输入IO口状态寄存器*/
gpio_adc_value_t  gpio_adc_va;          /*定义外部ADC输入的值*/
volatile uint8_t port_power_man_id;     /*GPIO管理ID*/

static void port_hand_read_task( void * pvParameters);
static void port_ext_gpio_init( void );
static void port_ext_gpio_st_set( gpio_input_channel_e channel , uint8_t level );
static uint32_t port_ext_gpio_stroke( gpio_input_channel_e channel , uint8_t level );
static void port_collect_ext_input_pin( void );
static void port_adc_gpio_init( void );
static void port_collect_adc_input_pin( void );

static uint32_t port_task_into_run_mode(void);
static uint32_t port_task_into_sleep_mode(void);
static uint32_t port_task_into_stop_mode(void);

#if 0
static void port_acc_pin_interrupt_cb(void* param);
static void port_acc_pin_interrupt_enable( void );
#endif
/** ****************************************************************************
* @remarks       void port_create_task(unsigned portBASE_TYPE uxPriority)
* @brief         创建外部引脚事件处理任务
* @param[in]     uxPriority 任务的优先级
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
void port_create_task(unsigned portBASE_TYPE uxPriority)
{
    memset( (uint8_t *)&gpio_input_st, 0x00, sizeof(gpio_input_state_t) );
    memset( (uint8_t *)&gpio_adc_va, 0x00, sizeof(gpio_adc_value_t) );
    /* 创建GPIO输入状态互斥体 */
    gpio_input_mutex = gaoz_mutex_create();
    if(gpio_input_mutex == 0)
    {
        while(1); /*创建信号量失败*/
    }
    /* 创建GPIO ADC 输入数值互斥体 */
    gpio_input_mutex = gaoz_mutex_create();
    if(gpio_input_mutex == 0)
    {
        while(1); /*创建信号量失败*/
    }
    port_adc_gpio_init();
    port_ext_gpio_init();
#if 0
    port_acc_pin_interrupt_enable();
#endif
    gaoz_thread_create(port_hand_read_task, PORT_MAN_NAME, 1024*2, NULL, uxPriority);
}

/** ****************************************************************************
* @remarks       static void port_adc_gpio_init( void )
* @brief         初始化ADC 接口
* @param[in]     无
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
static void port_adc_gpio_init( void )
{
    gaoz_hal_adc_init();
}

/** ****************************************************************************
* @remarks       static void port_ext_gpio_init( void )
* @brief         初始化外部输入IO口
* @param[in]     无
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
static void port_ext_gpio_init( void )
{
    /* INPUT 1 */
    gaoz_gpio_pull_disable(PORT_INPUT_EXT1_PIN);
    gaoz_gpio_mode_set(PORT_INPUT_EXT1_PIN,1);
    gaoz_gpio_cfg(PORT_INPUT_EXT1_PIN,0); /*配置为输入方式*/
    
    /* INPUT 2 */
    gaoz_gpio_pull_disable(PORT_INPUT_EXT2_PIN);
    gaoz_gpio_mode_set(PORT_INPUT_EXT2_PIN,1);
    gaoz_gpio_cfg(PORT_INPUT_EXT2_PIN,0); /*配置为输入方式*/
    /* INPUT 3 */
    gaoz_gpio_pull_disable(PORT_INPUT_EXT3_PIN);
    gaoz_gpio_mode_set(PORT_INPUT_EXT3_PIN,1);
    gaoz_gpio_cfg(PORT_INPUT_EXT3_PIN,0); /*配置为输入方式*/
    /* INPUT 4 */
    gaoz_gpio_pull_disable(PORT_INPUT_EXT4_PIN);
    gaoz_gpio_mode_set(PORT_INPUT_EXT4_PIN,1);
    gaoz_gpio_cfg(PORT_INPUT_EXT4_PIN,0); /*配置为输入方式*/
    /* INPUT 5 */
    gaoz_gpio_pull_disable(PORT_INPUT_EXT5_PIN);
    gaoz_gpio_mode_set(PORT_INPUT_EXT5_PIN,1);
    gaoz_gpio_cfg(PORT_INPUT_EXT5_PIN,0); /*配置为输入方式*/
    /* INPUT 6 */
    gaoz_gpio_pull_disable(PORT_INPUT_EXT6_PIN);
    gaoz_gpio_mode_set(PORT_INPUT_EXT6_PIN,0);
    gaoz_gpio_cfg(PORT_INPUT_EXT6_PIN,0); /*配置为输入方式*/
    /* INPUT 7 */
    gaoz_gpio_pull_disable(PORT_INPUT_EXT7_PIN);
    gaoz_gpio_mode_set(PORT_INPUT_EXT7_PIN,0);
    gaoz_gpio_cfg(PORT_INPUT_EXT7_PIN,0); /*配置为输入方式*/
    /* INPUT 8 */
    gaoz_gpio_pull_disable(PORT_INPUT_EXT8_PIN);
    gaoz_gpio_mode_set(PORT_INPUT_EXT8_PIN,0);
    gaoz_gpio_cfg(PORT_INPUT_EXT8_PIN,0); /*配置为输入方式*/
}
#if 0
/** ****************************************************************************
* @remarks       static void port_acc_pin_interrupt_cb(void* param)
* @brief         外部中端回调函数
* @param[in]     无
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
static void port_acc_pin_interrupt_cb(void* param)
{
	hal_gpioisr_t *isr_cfg = (hal_gpioisr_t*)param; 
	gaoz_gpio_get(PORT_INPUT_EXT8_PIN,&(isr_cfg->level));	
    port_ext_gpio_st_set( GET_INPUT_EXT8, isr_cfg->level );
    system_wakeup_queue_set( SYS_WAKEUP_TRIG_KL15 );
}

/** ****************************************************************************
* @remarks       static void port_acc_pin_interrupt_enable( void )
* @brief         使能ACC触发外部中断
* @param[in]     无
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
static void port_acc_pin_interrupt_enable( void )
{
    gaoz_gpio_pull_up_or_down( PORT_INPUT_EXT8_PIN , true );
    oc_isr_t g_oc_ist_prt = 
    {       
        .is_debounce = true,
        .intr_enable = true,
        .intr_level = false, 
        .intr_falling = true,
        .inte_rising = true, 
        .callback = port_acc_pin_interrupt_cb,
    };
    gaoz_gpio_mode_set(PORT_INPUT_EXT8_PIN,0);
    gaoz_gpio_cfg(PORT_INPUT_EXT8_PIN,0); /*配置为输入方式*/
    gaoz_gpio_isr_init(PORT_INPUT_EXT8_PIN,&g_oc_ist_prt);
}
#endif
/** ****************************************************************************
* @remarks       uint32_t port_adc_gpio_value_get( gpio_adc_channel_e channel )
* @brief         获取外部ADC 采集的数据
* @param[in]     channel 选择ADC的通道
* @param[out]    无
* @return        ADC数值
* @attention     无
*******************************************************************************/
uint32_t port_adc_gpio_value_get( gpio_adc_channel_e channel )
{
    uint32_t value = 0 ,osR = 0;
    if( gpio_adc_mutex != 0 )
    {   
        gaoz_mutex_lock( gpio_adc_mutex );
        osR = 1;
    }
    switch( channel )
    {
        case GET_ADC0:
            value = gpio_adc_va.adc0;
        break;
        case GET_ADC1:
            value = gpio_adc_va.adc1;
        break;
        case GET_ADC2:
            value = gpio_adc_va.adc2;
        break;
        default:
            value = 0;
        break;
    }
    if( osR == 1 )
    {   
        gaoz_mutex_unlock( gpio_adc_mutex );
    }
    return value;
}

/** ****************************************************************************
* @remarks       static void port_collect_adc_input_pin( void )
* @brief         获取ADC数据
* @param[in]     无
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
static void port_collect_adc_input_pin( void )
{
    uint32_t osR = 0;
    if( gpio_adc_mutex != 0 )
    {   
        gaoz_mutex_lock( gpio_adc_mutex );
        osR = 1;
    }
    /*获取ADC采集的电压值*/
    gaoz_hal_adc_get_data_polling( 2, (uint32_t *)&gpio_adc_va.adc0 );
    gaoz_hal_adc_get_data_polling( 3, (uint32_t *)&gpio_adc_va.adc1 );
    gaoz_hal_adc_get_data_polling( 1, (uint32_t *)&gpio_adc_va.adc2 );

    if( osR == 1 )
    {   
        gaoz_mutex_unlock( gpio_adc_mutex );
    }
}

/** ****************************************************************************
* @remarks       uint8_t port_ext_gpio_st_get( gpio_input_channel_e )
* @brief         获取外部IO口的状态
* @param[in]     channel 选择的获取IO的通道
* @param[out]    无
* @return        返回输入IO口的状态 0 低电平 1高电平
* @attention     无
*******************************************************************************/
uint8_t port_ext_gpio_st_get( gpio_input_channel_e channel )
{
    uint8_t level = 0 ,osR = 0;
    if( gpio_input_mutex != 0 )
    {   
        gaoz_mutex_lock( gpio_input_mutex );
        osR = 1;
    }
    switch( channel )
    {
        case GET_INPUT_EXT1:
            level = gpio_input_st.bport0;
        break;
        case GET_INPUT_EXT2:
            level = gpio_input_st.bport1;
        break;
        case GET_INPUT_EXT3:
            level = gpio_input_st.bport2;
        break;
        case GET_INPUT_EXT4:
            level = gpio_input_st.bport3;
        break;
        case GET_INPUT_EXT5:
            level = gpio_input_st.bport4;
        break;
        case GET_INPUT_EXT6:
            level = gpio_input_st.bport5;
        break;
        case GET_INPUT_EXT7:
            level = gpio_input_st.bport6;
        break;
        case GET_INPUT_EXT8:
            level = gpio_input_st.bport7;
        break;
        default:
        
        break;
    }
    if( osR == 1 )
    {   
        gaoz_mutex_unlock( gpio_input_mutex );
    }
    return level;
}

/** ****************************************************************************
* @remarks       uint8_t port_ext_gpio_st_get( gpio_input_channel_e )
* @brief         获取外部IO口的状态
* @param[in]     channel 选择的获取IO的通道
* @param[in]     level 设置IO的状态
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
static void port_ext_gpio_st_set( gpio_input_channel_e channel , uint8_t level )
{
    uint8_t osR = 0;
    if( gpio_input_mutex != 0 )
    {   
        gaoz_mutex_lock( gpio_input_mutex );
        osR = 1;
    }
    switch( channel )
    {
        case GET_INPUT_EXT1:
            gpio_input_st.bport0 = level;
        break;
        case GET_INPUT_EXT2:
            gpio_input_st.bport1 = level;
        break;
        case GET_INPUT_EXT3:
            gpio_input_st.bport2 = level;
        break;
        case GET_INPUT_EXT4:
            gpio_input_st.bport3 = level;
        break;
        case GET_INPUT_EXT5:
            gpio_input_st.bport4 = level;
        break;
        case GET_INPUT_EXT6:
            gpio_input_st.bport5 = level;
        break;
        case GET_INPUT_EXT7:
            gpio_input_st.bport6 = level;
        break;
        case GET_INPUT_EXT8:
            gpio_input_st.bport7 = level;
        break;
        default:
        
        break;
    }
    if( osR == 1 )
    {   
        gaoz_mutex_unlock( gpio_input_mutex );
    }
}

/** ****************************************************************************
* @remarks       static void port_ext_gpio_stroke( gpio_input_channel_e channel , uint8_t level )
* @brief         外部IO输入状态消除抖动
* @param[in]     channel 选择的获取IO的通道
* @param[in]     level 设置IO的状态
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
static uint32_t port_ext_gpio_stroke( gpio_input_channel_e channel , uint8_t level )
{
    uint8_t get_level = 0;
    uint32_t res = pdFAIL;
    uint8_t input_channel = (uint8_t)channel;
    get_level = port_ext_gpio_st_get( channel );
    if(( get_level != level ) && ( gpio_input_st.keystroke[input_channel] < 10 ))
    {
        gpio_input_st.keystroke[input_channel] ++;
    }
    else
    {
        if( gpio_input_st.keystroke[input_channel] != 0 )
        {
            gpio_input_st.keystroke[input_channel] = 0;
            res = pdPASS;
        }
    }
    return res;
}

/** ****************************************************************************
* @remarks       uint8_t port_collect_acc_pin_state_get( void )
* @brief         获取ACC 电源状态
* @param[in]     无
* @param[out]    无
* @return        1 高电平    0低电平
* @attention     无
*******************************************************************************/
uint8_t port_collect_acc_pin_state_get( void )
{
    uint8_t gpio_level = 0;
    //gaoz_gpio_get( PORT_INPUT_EXT8_PIN,(uint8_t *)&gpio_level );
    //port_ext_gpio_st_set( GET_INPUT_EXT8, gpio_level );
    return gpio_level;
}

/** ****************************************************************************
* @remarks       static port_collect_ext_input_pin( void )
* @brief         检测外部输入状态IO口
* @param[in]     无
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
static void port_collect_ext_input_pin( void )
{
    uint8_t gpio_level = 0;
    /*INPUT 1*/
    gaoz_gpio_get( PORT_INPUT_EXT1_PIN, (uint8_t *)&gpio_level );
    if( port_ext_gpio_stroke( GET_INPUT_EXT1 , gpio_level ) == pdPASS )
    {
        port_ext_gpio_st_set( GET_INPUT_EXT1, gpio_level );
        log_debug_printf(INFOR_MODE,PORT_MAN_NAME ,"PORT_INPUT_EXT1_PIN:%d\r\n", gpio_level );
    }
    /*INPUT 2*/
    gaoz_gpio_get( PORT_INPUT_EXT2_PIN,(uint8_t *)&gpio_level );
    if( port_ext_gpio_stroke( GET_INPUT_EXT2 , gpio_level ) == pdPASS )
    {
        port_ext_gpio_st_set( GET_INPUT_EXT2, gpio_level );
        log_debug_printf(INFOR_MODE,PORT_MAN_NAME ,"PORT_INPUT_EXT2_PIN:%d\r\n", gpio_level );
    }
    /*INPUT 3*/
    gaoz_gpio_get( PORT_INPUT_EXT3_PIN,(uint8_t *)&gpio_level );
    if( port_ext_gpio_stroke( GET_INPUT_EXT3 , gpio_level ) == pdPASS )
    {
        port_ext_gpio_st_set( GET_INPUT_EXT3, gpio_level );
        log_debug_printf(INFOR_MODE,PORT_MAN_NAME ,"PORT_INPUT_EXT3_PIN:%d\r\n", gpio_level );
    }
    /*INPUT 4*/
    gaoz_gpio_get( PORT_INPUT_EXT4_PIN,(uint8_t *)&gpio_level );
    if( port_ext_gpio_stroke( GET_INPUT_EXT4 , gpio_level ) == pdPASS )
    {
        port_ext_gpio_st_set( GET_INPUT_EXT4, gpio_level );
        log_debug_printf(INFOR_MODE,PORT_MAN_NAME ,"PORT_INPUT_EXT4_PIN:%d\r\n", gpio_level );
    }
    /*INPUT 5*/
    gaoz_gpio_get( PORT_INPUT_EXT5_PIN,(uint8_t *)&gpio_level );
    if( port_ext_gpio_stroke( GET_INPUT_EXT5 , gpio_level ) == pdPASS )
    {
        port_ext_gpio_st_set( GET_INPUT_EXT5, gpio_level );
        log_debug_printf(INFOR_MODE,PORT_MAN_NAME ,"PORT_INPUT_EXT5_PIN:%d\r\n", gpio_level );
    }
    /*INPUT 6*/
    gaoz_gpio_get( PORT_INPUT_EXT6_PIN,(uint8_t *)&gpio_level );
    if( port_ext_gpio_stroke( GET_INPUT_EXT6 , gpio_level ) == pdPASS )
    {
        port_ext_gpio_st_set( GET_INPUT_EXT6, gpio_level );
        log_debug_printf(INFOR_MODE,PORT_MAN_NAME ,"PORT_INPUT_EXT6_PIN:%d\r\n", gpio_level );
    }
    /*INPUT 7*/
    gaoz_gpio_get( PORT_INPUT_EXT7_PIN,(uint8_t *)&gpio_level );
    if( port_ext_gpio_stroke( GET_INPUT_EXT7 , gpio_level ) == pdPASS )
    {
        port_ext_gpio_st_set( GET_INPUT_EXT7, gpio_level );
        log_debug_printf(INFOR_MODE,PORT_MAN_NAME ,"PORT_INPUT_EXT7_PIN:%d\r\n", gpio_level );
    }
    /*INPUT 8*/
    gaoz_gpio_get( PORT_INPUT_EXT8_PIN,(uint8_t *)&gpio_level );
    if( port_ext_gpio_stroke( GET_INPUT_EXT8 , gpio_level ) == pdPASS )
    {
        port_ext_gpio_st_set( GET_INPUT_EXT8, gpio_level );
        log_debug_printf(INFOR_MODE,PORT_MAN_NAME ,"PORT_INPUT_EXT8_PIN:%d\r\n", gpio_level );
    }
}

/** ****************************************************************************
* @remarks       static uint32_t gpio_task_into_run_mode(void)
* @brief         GPIO任务进入运行状态
* @param[in]     无
* @param[out]    无
* @return        pdPASS 设置成功 pdFAIL 设置失败
* @attention     无
*******************************************************************************/
static uint32_t port_task_into_run_mode(void)
{
    task_modules_e state = TASK_MODE_INIT;
    uint32_t ret = pdFAIL;
    state = power_man_save_state_get( port_power_man_id ); /*获取任务的运行状态*/
    if( state != TASK_RUN_MODE )
    {
        power_man_save_state_set( port_power_man_id ,TASK_RUN_MODE );
        log_debug_send(INFOR_MODE,BAT_MAN_NAME ,"<<<<<<<<<<*****PORT task enters RUN mode*****>>>>>>>>>>\r\n", 0);
        ret = pdPASS;
    }
    else if( state == TASK_RUN_MODE )
    {
        ret = pdPASS;
    }
    return ret;
}
/** ****************************************************************************
* @remarks       static uint32_t gpio_task_into_sleep_mode(void)
* @brief         GPIO任务进入睡眠状态
* @param[in]     无
* @param[out]    无
* @return        pdPASS 设置成功 pdFAIL 设置失败
* @attention     无
*******************************************************************************/
static uint32_t port_task_into_sleep_mode(void)
{
    task_modules_e state = TASK_MODE_INIT;
    uint32_t ret = pdFAIL; 
    state = power_man_save_state_get( port_power_man_id ); /*获取任务的运行状态*/
    if( state != TASK_SLEEP_MODE )
    {
        power_man_save_state_set( port_power_man_id ,TASK_SLEEP_MODE );
        log_debug_send(INFOR_MODE,BAT_MAN_NAME ,"<<<<<<<<<<*****PORT task enters SLEEP mode*****>>>>>>>>>>\r\n", 0);
        ret = pdPASS;
    }
    else if( state == TASK_SLEEP_MODE )
    {
        ret = pdPASS;
    }
    return ret;
}
/** ****************************************************************************
* @remarks       static uint32_t gpio_task_into_stop_mode(void)
* @brief         GPIO任务进入停止状态
* @param[in]     无
* @param[out]    无
* @return        pdPASS 设置成功 pdFAIL 设置失败
* @attention     无
*******************************************************************************/
static uint32_t port_task_into_stop_mode(void)
{   
    task_modules_e state = TASK_MODE_INIT;
    uint32_t ret = pdFAIL;
    state = power_man_save_state_get( port_power_man_id ); /*获取任务的运行状态*/
    if( state != TASK_STOP_MODE )
    {   
        power_man_save_state_set( port_power_man_id ,TASK_STOP_MODE );
        log_debug_send(INFOR_MODE,BAT_MAN_NAME ,"<<<<<<<<<<*****PORT task enters STOP mode*****>>>>>>>>>>\r\n", 0);
        ret = pdPASS;
    }
    else if( state == TASK_STOP_MODE )
    {
        ret = pdPASS;
    }
    return ret;
}

/** ****************************************************************************
* @remarks       static void port_hand_read_task( void * pvParameters)
* @brief         PORT IO口数据读取任务
* @param[in]     * pvParameters 任务参数
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
static void port_hand_read_task( void * pvParameters)
{
    task_modules_e port_run_st;
    mon_reg_task_dog( 60 * GAOZ_TICK_PERIOD_S ,(uint8_t * )PORT_MAN_NAME , TASK_SEM_YES ); /*注册任务监控*/
    power_man_task_reg((uint8_t * )PORT_MAN_NAME,(uint8_t *)&port_power_man_id ); /*注册系统电源管理*/
    log_debug_send(DEBUG_MODE,PORT_MAN_NAME ,"Port management task started successfully\r\n",0);
    for( ;; )
    {   
        mon_reset_task_dog();
        port_run_st = power_man_task_state_get( port_power_man_id );          /*获取任务运行的状态*/
        /*******************************PORT任务处于运行状态***********************************/
        if(  port_run_st == TASK_RUN_MODE )                                   /*任务进入全速运行模式*/
        {
            if( port_task_into_run_mode() != pdPASS )                         /*判断睡眠是否设置成功，没有设置成功进入延时*/
            {
                gaoz_task_sleep(1000);
                continue;
            }
            port_collect_ext_input_pin();
            port_collect_adc_input_pin();
            gaoz_task_sleep( 100 ); 
        }
        /*******************************PORT任务处于休眠状态************************************/
        else if(  port_run_st == TASK_SLEEP_MODE )                           /*任务进入睡眠模式*/
        {
            if( port_task_into_sleep_mode() == pdPASS )              /*判断任务任务是否进入睡眠模式，进入睡眠模式后进行长时间延时*/ 
            {
                gaoz_task_sleep( 1000 );
                continue;
            }
            gaoz_task_sleep( 1000 );
        }
        /*******************************PORT任务处于停止状态************************************/
        else if(  port_run_st == TASK_STOP_MODE )                            /*任务进入睡眠模式*/
        {
            if( port_task_into_stop_mode() ==  pdPASS )              /*判断任务任务是否进入停止模式，进入停止模式后进行长时间延时*/ 
            {
                gaoz_task_sleep( 1000 );
                continue;
            }
            gaoz_task_sleep( 1000 );
        }
        /*******************************PORT任务空循环状态************************************/
        else                                      
        {
            port_collect_ext_input_pin();
            port_collect_adc_input_pin();
            gaoz_task_sleep( 100 ); 
        }
    }
}

